/*                   _   _ _ __                               *\
**     ________ ___ | | | | '_ \   scaup - Scala up!          **
**    / __/ __// _ || | | | |_) |  (c) 2008, Normen Mueller   **
**  __\ \/ /__/ __ || |_| | .__/   http://kwarc.info.nmueller **
** /____/\___/_/ |_/ \__,_|_|                                 **
**                                                            **
\*                                                            */
  
// $Id: SourceFile.scala 9 2008-05-24 12:12:30Z normen.mueller $

/* This class has its origin at: scala.tools.nsc.util.SourceFile */

package scaup.io.fs

object SourceFile {
  val LF: Char = 0x0A
  val FF: Char = 0x0C
  val CR: Char = 0x0D
  val SU: Char = 0x1A
  def isLineBreak(c: Int) = c match {
    case LF|FF|CR|SU => true
    case _ => false
  }
}

/** Abstract base class of a source file */
abstract class SourceFile {
  import SourceFile._
  
  def content : RandomAccessSeq[Char]
  
  def abstractfile : AbstractFile
  
  def length : Int
  
  override def toString(): String = abstractfile.name /* + ":" + content.length */
    
  def path = abstractfile.path
}

/** A file whose content does not change over time */
class StaticSourceFile(val abstractfile : AbstractFile, _content : Array[Char]) extends SourceFile {
  
  import SourceFile._
  
  def this(_file: AbstractFile) = this(_file, _file.toCharArray)
  
  def this(sourceName: String, content: Array[Char]) =
    this(new VirtualFile(sourceName), content)
    
  override def equals(that : Any) = that match {
    case that : StaticSourceFile => abstractfile == that.abstractfile
    case _ => false
  }
  override def hashCode = abstractfile.hashCode
    
  val content = _content
  
  override val length = content.length  
}

/** A source file composed of multiple other source files. */
class CompoundSourceFile(
    name: String,
    components: List[StaticSourceFile],
    contents: Array[Char]) extends StaticSourceFile(name, contents) {
  /** The usual constructor.  Specify a name for the compound file and a list of component sources.*/
  def this(name: String, components: StaticSourceFile*) = {
    this(
      name,
      components.toList,
      Array.concat(components.toList.map(comp => 
        CompoundSourceFile.stripSU(comp.content).toArray):_*))
  }

  /** Create an instance with the specified components and a generic name. */
  def this(components: StaticSourceFile*) =
    this("(virtual file)", components.toList:_*)
}

object CompoundSourceFile {
  private[io] def stripSU(chars: Array[Char]) =
    if (chars.length > 0 && chars.last == SourceFile.SU)
      chars.slice(0, chars.length-1)
    else
      chars
}


/** One portion of an underlying file.  The fragment includes the indeces from the specified start (inclusively) to stop (not inclusively). */
class SourceFileFragment(
    name: String,
    underlyingFile: StaticSourceFile,
    start: Int,
    stop: Int,
    contents: Array[Char]) extends StaticSourceFile(name, contents) {
  def this(name: String, underlyingFile: StaticSourceFile, start: Int, stop: Int) =
    this(
      name,
      underlyingFile,
      start,
      stop,
      { assert(start >= 0)
        assert(start <= stop)
        assert(start <= underlyingFile.length)
        assert(stop <= underlyingFile.length)
        underlyingFile.content.slice(start, stop).toArray })

  def this(underlyingFile: StaticSourceFile, start: Int, stop: Int) =
    this(
      "(fragment of " + underlyingFile.abstractfile.name + ")",
      underlyingFile,
      start,
      stop)
}
